#include "dswonvif_session.h"

CDswonvif_session::CDswonvif_session(LPST_ENV_T pEnv, char* pURL)
: m_pEnv(pEnv)
, m_bStopRecvStream(false)
, m_nRecvStreamThreadID(NULL)
{
	strcpy(m_sURL, pURL);
	if (m_nRecvStreamThreadID != NULL)
		return;
	pthread_mutex_init(&m_video_mem.lock, NULL);
	m_video_mem.seq = 0;
	
//	pthread_create(&m_nRecvStreamThreadID, NULL, CDswonvif_session::cbRecvStreamThreadFunc, (void*)this);
}

CDswonvif_session::~CDswonvif_session()
{
	if (m_nRecvStreamThreadID != NULL){
		m_bStopRecvStream = true;
		pthread_join(m_nRecvStreamThreadID, NULL);
	}
	while(!m_video_mem.vlist.empty()){
		LPST_VIDEO_FRAME_T pNode = m_video_mem.vlist.front();
		m_video_mem.vlist.pop_front();
		if (pNode->pFrame != NULL)
			delete pNode->pFrame;
		delete pNode;
	}
	pthread_mutex_destroy(&m_video_mem.lock);
}

void CDswonvif_session::RecvStreamThreadFunc()
{
	LOG4CPLUS_DEBUG(log_dsw, "Start Recv thread function!");


	AVFormatContext* context = avformat_alloc_context();
	int video_stream_index;
	AVDictionary* options = NULL;
	av_dict_set(&options, "rtsp_transport", "tcp", 0);

	context->interrupt_callback.callback = CDswonvif_session::decode_interrupt_cb;
	context->interrupt_callback.opaque = this;

	if(avformat_open_input(&context, m_sURL, NULL, &options) != 0){
		LOG4CPLUS_DEBUG(log_dsw, "avformat_open_input failed!");
		goto END_RECVSTREAM;
	}

	if(avformat_find_stream_info(context, NULL) < 0){
		LOG4CPLUS_DEBUG(log_dsw, "avformat_find_stream_info failed!");
		goto END_RECVSTREAM;
	}

	for(int i = 0; i < context->nb_streams; i++){
		if(context->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO){
			video_stream_index = i;
			break;
		}
	}

	av_dump_format(context, 0, context->filename, 0);
	
	AVPacket packet;
	av_init_packet(&packet);

//	FILE* fp;
//	fp = fopen("/mnt/nfs/test.dat", "wb");
	while(!m_pEnv->bExit && !m_bStopRecvStream){
		if (av_read_frame(context, &packet) >= 0){
			if (packet.stream_index == video_stream_index){
				printf("xxxx = %d, key = %d\n", packet.size, packet.flags & AV_PKT_FLAG_KEY);
				for (int j = 0; j < 48; j++)
					printf("%02x, ", packet.data[j]);
				printf("\n");
//				fwrite(packet.data, 1, packet.size, fp);
				PutFrameToMem(&packet);
			}
		}
		av_free_packet(&packet);
		av_init_packet(&packet);
		usleep(10);
	}
//	fclose(fp);
	av_free_packet(&packet);
	av_read_pause(context);

END_RECVSTREAM:
	avformat_free_context(context);
	
	LOG4CPLUS_DEBUG(log_dsw, "Exit Recv thread function!");
}

void CDswonvif_session::PutFrameToMem(AVPacket* pFrame)
{
	int nNULSize;
	if (memcmp(pFrame->data, "\x00\x00\x00\x01", 4) == 0)
		nNULSize = 4;
	else if (memcmp(pFrame->data, "\x00\x00\x01", 3) == 0)
		nNULSize = 3;
	else{
		LOG4CPLUS_WARN(log_dsw, "Not valid video frame data!");
		return;
	}
	pthread_mutex_lock(&m_video_mem.lock);
	LPST_VIDEO_FRAME_T pNode;
	int nNewSize;
	if (nNULSize == 4)
		nNewSize = pFrame->size;
	else{
		if ((pFrame->flags & AV_PKT_FLAG_KEY))
			nNewSize = pFrame->size + 1 * 10;
		else
			nNewSize = pFrame->size + 1;
	}
	if (m_video_mem.vlist.size() < MAX_FRAMES){
		pNode = new ST_VIDEO_FRAME_T;
		pNode->pFrame = new unsigned char[nNewSize];
	}
	else{
		pNode = m_video_mem.vlist.front();
		m_video_mem.vlist.pop_front();
		if (pNode->length < nNewSize){
			delete pNode->pFrame;
			pNode->pFrame = new unsigned char[nNewSize];
		}
	}
	pNode->is_keyframe = (pFrame->flags & AV_PKT_FLAG_KEY);
	pNode->seq = m_video_mem.seq++;
	pNode->length = nNewSize;
	if (nNULSize == 4)
		memcpy(pNode->pFrame, pFrame->data, pFrame->size);
	else{
		if (pFrame->flags & AV_PKT_FLAG_KEY){
			int nTotalLen = pFrame->size;
			unsigned char* pPos = pFrame->data;
			unsigned char* pDest = pNode->pFrame;
			int i = nNULSize;
			int ncount = 0;
			while (i < (nTotalLen - nNULSize)){
				if ((memcmp(pPos, "\x00\x00\x01", 3) == 0) && (memcmp(&pPos[i], "\x00\x00\x01", 3) != 0)){
					i++;
					continue;
				}
				pDest[0] = 0x00;
				memcpy(pDest + 1, pPos, i);
				pDest += (i + 1);
				pPos += i;
				i = nNULSize;
				ncount++;
				if ((pPos[i] & 0x1f) == 0x05)
					break;
			}
			pDest[0] = 0x00;
			memcpy(pDest + 1, pPos, (nTotalLen - (pPos - pFrame->data)));
			ncount++;
			pNode->length = pFrame->size + ncount;
		}
		else{
			pNode->pFrame[0] = 0x00;
			memcpy(pNode->pFrame + 1, pFrame->data, pFrame->size);
		}
	}
	gettimeofday(&pNode->timestamp, NULL);
#if 0
	printf("aaa = %d, key = %d\n", pNode->length, pNode->is_keyframe);
	for (int j = 0; j < 48; j++)
		printf("%02x, ", pNode->pFrame[j]);
	printf("\n");
	{
		if (pNode->is_keyframe){
			int nTotalLen = pNode->length;
			unsigned char* pPos = pNode->pFrame;
			int nppslen;
			int i = 4;
			while (i < (nTotalLen - 4)){
				if ((memcmp(pPos, "\x00\x00\x00\x01", 4) == 0) && (memcmp(&pPos[i], "\x00\x00\x00\x01", 4) != 0)){
					i++;
					continue;
				}
				if ((pPos[4] & 0x1f) == 0x08){
					nppslen = i;
					break;
				}
				pPos += i;
				i = 4;
			}
			printf("ppslen = %d\n", nppslen);
			for (i = 0 ; i < nppslen; i++)
				printf("%02x, ", pPos[i]);
			printf("\n");
		}
	}
#endif
	m_video_mem.vlist.push_back(pNode);
	pthread_mutex_unlock(&m_video_mem.lock);
}

